package thimeeeee.Model;

import thimeeeee.Control.GameController;
//import thimeeeee.Skeleton;

public class Game {

    GameInfo userinfo;
    private LevelFactory levelfactory;
	private Level _level;
    //a jelenlegi pálya száma
    private int numLevel = 1;
	GameController gameController;
	Player player1, player2;
	Diamond diamond;
    
    //a proto teszteléséhez szükségünk van referenciákra az egyes szörnyekre
    //a szörnyek száma a fajtájuk kódjával egyezik meg
    public Beast b0, b1, b2, b3, b4, b5, b6, b7;

    //konstruktor paraméter nélküli indításhoz, ekkor az 1. pálya indul
    public Game(GameController gc)
    {
//        Skeleton.Create("Game");
//        Skeleton.StartFunc("Game()");
        Init(numLevel);
        gameController = gc;
//        Skeleton.EndFunc("Game()", "void");
    }

    public Game(int level, GameController gc)
    {
//        Skeleton.Create("Game");
//        Skeleton.StartFunc("Game()");
        numLevel = level;
        Init(level);
        gameController = gc;
//        Skeleton.EndFunc("Game()", "void");
    }

    public Level GetLevel()
    {
        return _level;
    }

    public Player GetPlayer(int i)
    {
        if (i == 2)
        {
            return player2;
        }
        else return player1;
    }

    public GameInfo GetGameInfo()
    {
        return userinfo;
    }
	
    // Játék inicializálása
    public void Init(int level) {
//		Skeleton.StartFunc("Game.Init()");
        //GameInfo példányosítása
        //player = new Player(this);
        //GameInfo példányosítása
        levelfactory = new LevelFactory(this);
        //GameInfo példányosítása
        userinfo = new GameInfo(this);
        //Az aktuális szint lekérése a levelfactory-tól, ez jelen esetben az 1. pálya
        _level = levelfactory.GetLevel(level);
        if(player1 != null) player1.level = _level;
        if(player2 != null) player2.level = _level;
        //referencia a gameinfonak a pályáról, ez a kijárat megnyitásához kell
        userinfo.SetLevel(_level);
        
//        Skeleton.EndFunc("Game.Init()", "void");
    }

    public void NextLevel(){
        gameController.Start(numLevel + 1);
    }

    //Játékos megölése
	public void KillPlayer() {
//		Skeleton.StartFunc("Game.KillPlayer()");
        userinfo.KillPlayer();
//        Skeleton.EndFunc("Game.KillPlayer()", "void");
	}

    //Szint újrakezdése
	public void RestartLevel() {
//		Skeleton.StartFunc("Game.RestartLevel()");

        int lives = userinfo.GetLives();

        gameController.Start(numLevel, lives);

//        _level = levelfactory.GetLevel();
//
//        if(player1 != null) player1.level = _level;
//        if(player2 != null) player2.level = _level;
//        //referencia a gameinfonak a pályáról, ez a kijárat megnyitásához kell
//        userinfo.SetLevel(_level);
//
//        userinfo.SetLives(lives);

        //A tesztelés alatt nem indítunk új pályát!!!!!!!

//        int stage = userinfo.GetLevel();
//        //ideiglenesen tároljuk az életek korábbi számát
//        int lives = userinfo.GetLives();
//
//        levelfactory.GetLevel(stage);
//        //majd a tárolt értéket állítjuk vissza
//        userinfo.SetLives(lives);
//        userinfo = new GameInfo(this);

//        Skeleton.EndFunc("Game.RestartLevel()", "void");
	}

    //Játék vége
	public void EndGame() {
//		Skeleton.StartFunc("Game.EndGame()");
        System.out.println("Game Over");
        
        gameController.GameEnd();
//        Skeleton.EndFunc("Game.EndGame()", "void");
	}

    //Gyémántok számának növelése
	public void IncDiamond() {
		userinfo.IncDiamonds();
	}

    public void Idle(double aTimeStamp){
        _level.Idle(aTimeStamp);
    }

    //a térképet karaktertömbbé alakító eljárás
    public char[][] GetStringMap()
    {
//        Skeleton.StartFunc("Game.GetStringMap");
        //bejárja az összes játéktéren lévő fieldet, majd string tömbben adja vissza azt
        //a proto teszteléséhez szükséges

        //kihasználjuk, hogy a térkép ilyenkor már mindenképpen tömbbe rendezhető (az üres mezőket fallal töltöttük fel)
        //és soronként olvassuk ki a láncba kapcsolt elemeket

        char[][] map = new char[_level.maxHeight][_level.maxWidth];
        //értékek nullázása
        for (int i = 0; i < _level.maxHeight; i++)
        {
            for (int j = 0; j < _level.maxWidth; j++)
            {
                map[i][j] = ' ';
            }
        }

        Field rowF = _level.field;
        Field f = rowF;

        //sor
        int i = 0;
        //oszlop
        int j = 0;

        //elemek beolvasásának sorrendje:
        /*
         * 1   3   5
         *   2   4
         * 6   8   10
         *   7   9
         */
        //ciklus az utolsó sorig
        while(rowF != null)
        {
            j = 0;
            //ciklus az utolsó oszlopig
            while(f != null)
            {
                if (f.HasChanged()){
                    if (!f.IsEmpty())
                    {
                        ElementBase[] b = f.GetElements();
                        if (b[0] != null)
                        {
                            if (b[0].getClass() == Soil.class){
                                map[i][j] = '#';
                            }
                            if (b[0].getClass() == Granite.class){
                                map[i][j] = 'g';
                            }
                            if (b[0].getClass() == Wall.class){
                                map[i][j] = '*';
                            }
                            if (b[0].getClass() == Exit.class){
                                map[i][j] = 'e';
                            }
                            if (b[0].getClass() == Rock.class){
                                map[i][j] = 'r';
                            }
                            if (b[0].getClass() == Diamond.class){
                                map[i][j] = 'd';
                            }
                            if (b[0].getClass() == Bomb.class){
                                map[i][j] = 'b';
                            }
                            if (b[0].getClass() == Player.class){
                                //a két játékos megkülönböztetése a referencia alapján
                                if (b[0].equals(player1)){
                                    map[i][j] = 'k';
                                    // ha egy mezőn áll egy bomba, és egy játékos
                                    if(b[1]!= null && b[1].getClass() == Bomb.class)
                                    {
                                        map[i][j] = 'c';
                                    }
                                }
                                else{
                                    map[i][j] = 'l';
                                    // ha egy mezőn áll egy bomba, és egy játékos
                                    if(b[1]!= null && b[1].getClass() == Bomb.class)
                                    {
                                        map[i][j] = 'n';
                                    }
                                }
                            }
                            if (b[0].getClass() == Beast.class){
                                //a szörnyek tulajdonságait a számuk alapján határozzuk meg
                                //ennek visszafejtéséhez egy int tömbben megnöveljük azokat az indexeket, amely
                                //számával megegyező szörny az adott tulajdonság vizsgálata után még szóba jöhet
                                //a végén csak 1 szám értéke a legnagyobb, az a szörny száma
                                Beast sz = (Beast)b[0];
                                /* Szama:   0   1   2   3   4   5   6   7
                                 * Koveto       x       x       x       x
                                 * Reprod           x   x           x   x
                                 * Gyemant                  x   x   x   x
                                 */
                                int[] szamok = {0, 0, 0, 0, 0, 0, 0, 0};
                                if (sz._isDiamond){
                                    szamok[4]++;
                                    szamok[5]++;
                                    szamok[6]++;
                                    szamok[7]++;
                                }
                                if (sz._isReproducing){
                                    szamok[2]++;
                                    szamok[3]++;
                                    szamok[6]++;
                                    szamok[7]++;
                                }
                                if (sz._isTracing){
                                    szamok[1]++;
                                    szamok[3]++;
                                    szamok[5]++;
                                    szamok[7]++;
                                }
                                int beastSzam = 0;  //alapértelmezett az alap szörny
                                for (int e = 1; e < 8; e++)
                                {
                                    if (szamok[e] > szamok[beastSzam]){
                                        beastSzam = e;
                                    }
                                }
                                map[i][j] = (char)(beastSzam + '0');
                            }
                        }
                    }
                    else
                    {
                        //egyébként üres mező
                        map[i][j] = '-';
                    }
                    //a változást már kezeltük, így újra "változatlan" állapotba kerül a mező
                    f.UnSetChanged();
                }

                //ugrás a következő mezőre
                if (i % 2 == 0){
                    //ha már nincs több sor, akkor az utolsó sor elemeit nem tudjuk a korábbi algoritmussal elérni
                    if (f.GetNeighbor(Direction.downright) == null){
                        /* Új módszer:
                         *   2   4
                         * 1   3   5
                         */
                        if (f.GetNeighbor(Direction.upright) != null){
                            Field f2 = f.GetNeighbor(Direction.upright);
                            if (f2.GetNeighbor(Direction.downright) != null){
                                f = f2.GetNeighbor(Direction.downright);
                                j++;

                                //így az 1-es mezőből a 3-asba léptünk, és a kiírandó mapben 1-et léptünk jobbra
                            }
                            //ha már így sincs találat, akkor a pálya végére értünk
                            else f = null;
                        }
                        //ha már így sincs találat, akkor a pálya végére értünk
                        else f = null;
                    }
                    //egyébként az eddigi bejárás is jó
                    else{
                    f = f.GetNeighbor(Direction.downright);
                    i++;
                    }
                }
                else {
                    f = f.GetNeighbor(Direction.upright);
                    i--;
                    j++;
                }
            }

            //következő sor
            rowF = rowF.GetNeighbor(Direction.down);
            f = rowF;
            
            if(i%2 == 0) i += 2;
            else i++;
        }

//        // reduce map
//        int x = 0;
//        int y = 0;
//
//        for(int k = 0; k < map.length; k++)
//        {
//            int ltemp = map[k].length;
//
//            for(int l = ltemp - 1; l >= 0 ; l--)
//            {
//                if(l == 0)
//                    y = k;
//
//                if(map[k][l] != ' ')
//                {
//                    if(l > x) x = l + 1;
//
//                    break;
//                }
//            }
//
//            if(y != 0)
//                break;
//        }
//
//        if(y == 0) y = 200;
//
//        char[][] retMap = new char[y][x];
//
//        for(int ny = 0; ny < y; ny++)
//        {
//            for(int nx = 0; nx < x; nx++)
//            {
//                retMap[ny][nx] = map[ny][nx];
//            }
//        }

////        Skeleton.EndFunc("Game.GetStringMap", "map");
        
        return map;
    }
}